#!/usr/bin/python

# Clicco is a simple utility GUI for constucting command line commands with arguments.
# Copyright (C) 2011 - Teuvo Eloranta

from PythonCard import model, dialog
import glob, os
from wx import ICON_INFORMATION
from wx import OK as WX_OK

# User can change these:
ARG_LAST_CHAR_REMOVED = "&"                                     # last argument chosen to command might need this character removed
REMOVE_LAST_ARG_CHAR = True                                     # True if removed, 'False' if not (case sensitive value, do not use 'true' or 'TRUE' !)
COMMENT_SEPARATOR = "##"                                           # argument line can have comment after these characters in the line

# User should not change these:
CLICCO_VERSION = "1.0 Beta-2"
ARG_COUNT = 12
STR_CANCEL_PRESS = "Cancel pressed in dialog"
CMD_DIR_PREFIX = "cmd_*"                                        # The prefix for recognizing command directories
HELP_TEXT = """
Clicco - Command Line Interface Command COnstructor.

Purpose:
----------
Clicco is a simple utility GUI for constucting command line commands with arguments.

Usage:
--------
Select a command from the menu (cmd_default used by defautl), commands equal the directories in Clicco's root directory starting with "cmd_".
Each command can have up to 12 arguments, which correspond to "param<nbr>_config.txt" files in the command's directory.
After selecting your arguments from the 12 choice widgets, press button 'Generate' the call is generated to the text area.
If you uncheck a checkbox in front of the argument choice widget, the argument is not generated into the call.
If you uncheck the "Remove" checkbox, the last special character will not be moved from the command. 
The special character is by default '&' and can be changed in the clicco.py file, see variable 'ARG_LAST_CHAR_REMOVED'. 

Argument file structure:
----------------------------
1st line in the file is the name that is shown before the argument choice widget.
Next lines are the values for the choice widget.

Creating new choices to choice widget:
--------------------------------------------
If you press the "N<nbr>" button, there will be a prompt which asks which new choice text you want to add. 
If there is any text selected in the choice widget, that is used as the basis for the widget text.
The new choice is written into the corresponding argument file and added to the choice widget as last item.

Clicco comes with some dummy command folders and argument files, just to show you how the tool works.
Just take a look at those and create your own ones.

Requirements:
---------------
- Python 2.6 (Tested with this one, should work with earlier too)
- wxPython for the Python release used
- Pythoncard 0.8.2


More instructions on the Clicco homepage (wiki):
http://http://code.google.com/p/clicco/

"""

class clicco(model.Background):

  def on_initialize(self, event):
    """
    This is executed when clicco is initialized
    """
    self.sCurrentCommand = "cmd_default"                         # = cmd_* directory name in the Clicco dir
    self.lstToolTips = [""] * ARG_COUNT
    self.fnLoadParameters()
    self.components.Remove.checked = REMOVE_LAST_ARG_CHAR
    self.components.Remove.toolTip = "If checked the last argument's special character '%s' is removed" % ARG_LAST_CHAR_REMOVED

    
  def fnUnCheckArgCheckBoxes(self):
    """
    Uncheck all argument's checkboxes
    """
    for i in range(ARG_COUNT):
      eval("self.components.checkBoxPar" + str(i+1)).checked = False


  def fnResetToolTips(self):
    """
    Set tooltips to argument choice widgets
    """
    for i in range(ARG_COUNT):
      eval("self.components.choicePar" + str(i+1)).toolTip = "Choose an argument value"
      
      
  def fnLoadParameters(self):
    """
    Fill parameter labels and values to choice widgets,
    uncheck checkboxes and reset argument tool tips
    """
    self.lstToolTips = [""] * ARG_COUNT
    for i in range(ARG_COUNT):
      iLineNbr = 1
      lstLines = []
      try:
        for sLine in open(self.sCurrentCommand + os.sep + "param" + str(i+1) + "_config.txt"): 
          iLineNbr += 1
          if not sLine.startswith("#") and len(sLine)>1:          # don't read comment lines or empty lines to list
            lstTmp = sLine.split(COMMENT_SEPARATOR)
            if len(lstTmp) > 1:                                                   # possible comment
              lstLines.append(lstTmp[0] + "\n" + lstTmp[1].strip())  # add argument and comment
            else:
              lstLines.append(sLine.strip("\n")) 
      except IOError:                                             # don't require all 12 argument files to exist
        continue
      eval("self.components.txtPar" + str(i+1)).text = lstLines[0].strip()
      eval("self.components.choicePar" + str(i+1)).items = lstLines[1:]
      self.title = "Clicco - command: %s" % self.sCurrentCommand
    self.fnUnCheckArgCheckBoxes()
    self.fnResetToolTips()


  def on_Generate_mouseClick(self, event):
    """
    Form a command based on user selections
    """
    sCmd = ""
    print "\n"
    for i in range(ARG_COUNT):
      if eval("self.components.checkBoxPar" + str(i+1) + ".checked"):
        sTmp = eval("self.components.choicePar" + str(i+1) +
                     ".stringSelection.strip(\"\\n\")")
        print "chosen: '%s'" % sTmp.split("\n")[0]
        sCmd += sTmp.split("\n")[0]
    if REMOVE_LAST_ARG_CHAR:
      if sCmd[-1] == ARG_LAST_CHAR_REMOVED:
       sCmd = sCmd[:-1]                                             # remove the defined last char from end, if has one
    self.components.txtCommands.text = self.components.txtCommands.text + sCmd + "\n"

    
  def fnGenerateNewArgument(self, iParNbr):
    """
    Add the argument asked from the user to the list and to the file
    """
    sSelectedArg = eval("self.components.choicePar" + str(iParNbr) +
                        ".stringSelection.strip()")
    objRes = dialog.textEntryDialog(self, 
                                    'Save a new argument choice, or press cancel',
                                    'New argument', 
                                    '%s' % sSelectedArg)
    if objRes.accepted:
      sTmp = objRes.text.replace("\"", "\\\"")                       # eval command needs the quotation marks escaped!
      eval("self.components.choicePar" + str(iParNbr) + ".append(\"%s\")" % sTmp)
      fp = open(self.sCurrentCommand + os.sep + "param" + str(iParNbr) + "_config.txt", "a")
      fp.write("\n" + sTmp)
      fp.close()

  
  def lstFnGetCmdDirs(self):
    """
    return all the command directory names
    """
    lstCmdDirs = glob.glob(CMD_DIR_PREFIX)
    for sItem in lstCmdDirs:
      if not os.path.isdir(sItem):
        lstCmdDirs.remove(sItem)
    return lstCmdDirs


  def fnAskCommandUsed(self):
    """
    Ask from user which command (=directory) is used,
    return the selected command
    """
    lstCmdDirs = self.lstFnGetCmdDirs()
    objRes = dialog.singleChoiceDialog(self, "Select a command", "Command selection", lstCmdDirs)
    if objRes.accepted:
      return objRes.selection
    return STR_CANCEL_PRESS


  def fnSetArgToolTip(self, iArgNbr, sArgTxt):
    lstTmp = sArgTxt.split("\n")
    if len(lstTmp) > 1:
      eval("self.components.choicePar" + str(iArgNbr)).toolTip = "%s" % lstTmp[1]
    else:
      eval("self.components.choicePar" + str(iArgNbr)).toolTip = "No tip defined"


  # Handle menus:
  
  def on_menuCommandLoad_select(self, event):
    """
    Load argument choices for the selected command
    """
    sCommand = self.fnAskCommandUsed()
    if not sCommand == STR_CANCEL_PRESS:
      self.sCurrentCommand = sCommand
      self.fnLoadParameters()


  def on_menuHelpInstructions_select(self, event):
    """
    Instructions dialog
    """
    objRes = dialog.scrolledMessageDialog(self, message=HELP_TEXT, title="Clicco instructions")


  def on_menuHelpAbout_select(self, event):
    """
    About dialog
    """
    MSG = "Clicco v. %s \n\nBy Teuvo Eloranta\nteuvoe AT gmail dot com\n\nLicense: GNU GPL v3\n\n\nhttp://code.google.com/p/clicco/" % CLICCO_VERSION
    objRes = dialog.messageDialog(self, MSG, 'About Clicco', ICON_INFORMATION | WX_OK)


  # Check a checkbox, if corresponding item is selected:
  
  def on_choicePar1_select(self, event):
    self.components.checkBoxPar1.checked = True
    self.fnSetArgToolTip(1, self.components.choicePar1.stringSelection)
  
  def on_choicePar2_select(self, event):
    self.components.checkBoxPar2.checked = True
    self.fnSetArgToolTip(2, self.components.choicePar2.stringSelection)
    
  def on_choicePar3_select(self, event):
    self.components.checkBoxPar3.checked = True
    self.fnSetArgToolTip(3, self.components.choicePar3.stringSelection)
    
  def on_choicePar4_select(self, event):
    self.components.checkBoxPar4.checked = True
    self.fnSetArgToolTip(4, self.components.choicePar4.stringSelection)
    
  def on_choicePar5_select(self, event):
    self.components.checkBoxPar5.checked = True
    self.fnSetArgToolTip(5, self.components.choicePar5.stringSelection)
    
  def on_choicePar6_select(self, event):
    self.components.checkBoxPar6.checked = True
    self.fnSetArgToolTip(6, self.components.choicePar6.stringSelection)
    
  def on_choicePar7_select(self, event):
    self.components.checkBoxPar7.checked = True
    self.fnSetArgToolTip(7, self.components.choicePar7.stringSelection)
    
  def on_choicePar8_select(self, event):
    self.components.checkBoxPar8.checked = True
    self.fnSetArgToolTip(8, self.components.choicePar8.stringSelection)
    
  def on_choicePar9_select(self, event):
    self.components.checkBoxPar9.checked = True
    self.fnSetArgToolTip(9, self.components.choicePar9.stringSelection)
        
  def on_choicePar10_select(self, event):
    self.components.checkBoxPar10.checked = True
    self.fnSetArgToolTip(10, self.components.choicePar10.stringSelection)
        
  def on_choicePar11_select(self, event):
    self.components.checkBoxPar11.checked = True
    self.fnSetArgToolTip(11, self.components.choicePar11.stringSelection)
        
  def on_choicePar12_select(self, event):
    self.components.checkBoxPar12.checked = True
    self.fnSetArgToolTip(12, self.components.choicePar12.stringSelection)


  # Generate a new parameter based on the selected one:
  
  def on_N1_mouseClick(self, event):
    self.fnGenerateNewArgument(1)
    
  def on_N2_mouseClick(self, event):
    self.fnGenerateNewArgument(2)
    
  def on_N3_mouseClick(self, event):
    self.fnGenerateNewArgument(3)

  def on_N4_mouseClick(self, event):
    self.fnGenerateNewArgument(4)
    
  def on_N5_mouseClick(self, event):
    self.fnGenerateNewArgument(5)
    
  def on_N6_mouseClick(self, event):
    self.fnGenerateNewArgument(6)
    
  def on_N7_mouseClick(self, event):
    self.fnGenerateNewArgument(7)
    
  def on_N8_mouseClick(self, event):
    self.fnGenerateNewArgument(8)
    
  def on_N9_mouseClick(self, event):
    self.fnGenerateNewArgument(9)
    
  def on_N10_mouseClick(self, event):
    self.fnGenerateNewArgument(10)
        
  def on_N11_mouseClick(self, event):
    self.fnGenerateNewArgument(11)
        
  def on_N12_mouseClick(self, event):
    self.fnGenerateNewArgument(12)

  # 'Remove' checkbox:
  
  def on_Remove_mouseClick(self, event):
    """
    Remove checkbox is clicked, set the mode to either remove
    or not remove tha last argument's special character
    """
    global REMOVE_LAST_ARG_CHAR
    REMOVE_LAST_ARG_CHAR = self.components.Remove.checked
    
    
if __name__ == '__main__':
    app = model.Application(clicco)
    app.MainLoop()

